/**
 * 
 */
package org.seckill.util.redis;

import java.io.Serializable;
import java.util.concurrent.TimeUnit;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

/**
 * 
 * @author yue
 * 2016年6月19日 下午2:43:04
 */
public class MethodCacheInterceptor implements MethodInterceptor {
	private RedisTemplate<Serializable, Object> redisTemplate;
	private ThreadPoolTaskExecutor threadPoolTaskExecutor;
    private Long defaultCacheExpireTime = 10l; // 缓存默认的过期时间,这里设置了10秒

	/* 
	 * @param invocation
	 * @return
	 * @throws Throwable 
	 */
	@Override
	public Object invoke(MethodInvocation invocation) throws Throwable {
		Object value = null;
		//目标类
		String targetClassName = invocation.getThis().getClass().getName();
		//目标方法
		String targetMethodName = invocation.getMethod().getName();
		//方法入参
		Object[] arguments = invocation.getArguments();
		String key = getCacheKey(targetClassName, targetMethodName, arguments);
		try {
			//判断是否有缓存
			if(exists(key)){
				return getCache(key);
			}
			//写入缓存
			value = invocation.proceed();
			if(value != null){
				final String tkey = key;
				final Object tvalue = value;
				threadPoolTaskExecutor.execute(new Runnable(){
					@Override
					public void run() {
						setCache(tkey, tvalue, defaultCacheExpireTime);
					}
				});
			}
		} catch (Exception e) {
			e.printStackTrace();
            if (value == null) {
                return invocation.proceed();
            }
		}
		return value;
	}

	/**
	 * 写入缓存
	 * @param tkey
	 * @param tvalue
	 * @param defaultCacheExpireTime2
	 */
	protected boolean setCache(String tkey, Object tvalue,
			Long defaultCacheExpireTime) {
		boolean result = false;
		try {
			ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
			operations.set(tkey, tvalue);
			redisTemplate.expire(tkey, defaultCacheExpireTime, TimeUnit.SECONDS);
			result = true;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return result;
	}

	/**
	 * 读取缓存
	 * @param key
	 * @return
	 */
	private Object getCache(final String key) {
		ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
		return operations.get(key);
	}

	/**
	 * 判断缓存中是否有对应的value
	 * @param key
	 * @return
	 */
	private boolean exists(String key) {
		 return redisTemplate.hasKey(key);
	}

	/**
	 * 生成缓存key
	 * @param targetClassName
	 * @param targetMethodName
	 * @param arguments
	 * @return
	 */
	private String getCacheKey(String targetClassName, String targetMethodName,
			Object[] arguments) {
		StringBuffer sbu = new StringBuffer();
		sbu.append(targetClassName).append("_").append(targetMethodName);
		if(arguments != null){
			for (int i = 0; i < arguments.length; i++) {
				sbu.append("_").append(arguments[i]);
			}
		}
		return sbu.toString();
	}

	public void setRedisTemplate(RedisTemplate<Serializable, Object> redisTemplate) {
		this.redisTemplate = redisTemplate;
	}

	public void setThreadPoolTaskExecutor(
			ThreadPoolTaskExecutor threadPoolTaskExecutor) {
		this.threadPoolTaskExecutor = threadPoolTaskExecutor;
	}

}
